﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace YiJing.Model
{
    public sealed class HexagramFigure : LineFigure
    {
        private static readonly int[,] Lookup = new int[8, 8]
        {
            { 02, 23, 08, 20, 16, 35, 45, 12 },
            { 15, 52, 39, 53, 62, 56, 31, 33 },
            { 07, 04, 29, 59, 40, 64, 47, 06 },
            { 46, 18, 48, 57, 32, 50, 28, 44 },
            { 24, 27, 03, 42, 51, 21, 17, 25 },
            { 36, 22, 63, 37, 55, 30, 49, 13 },
            { 19, 41, 60, 61, 54, 38, 58, 10 },
            { 11, 26, 05, 09, 34, 14, 43, 01 },
        };

        public static readonly string[] Interpretations = new[]
        {
            "Possessing Creative Power & Skill",
            "Needing Knowledge & Skill; Do not force matters and go with the flow",
            "Sprouting",
            "Detained, Enveloped and Inexperienced",
            "Uninvolvement (Wait for now), Nourishment",
            "Engagement in Conflict",
            "Bringing Together, Teamwork",
            "Union",
            "Accumulating Resources",
            "Continuing with Alertness",
            "Pervading",
            "Stagnation",
            "Fellowship, Partnership",
            "Independence, Freedom",
            "Being Reserved, Refraining",
            "Inducement, New Stimulus",
            "Following",
            "Repairing",
            "Approaching Goal, Arriving",
            "The Withholding",
            "Deciding",
            "Embellishing",
            "Stripping, Flaying",
            "Returning",
            "Without Rashness",
            "Accumulating Wisdom",
            "Seeking Nourishment",
            "Great Surpassing",
            "Darkness, Gorge",
            "Clinging, Attachment",
            "Attraction",
            "Perseverance",
            "Withdrawing",
            "Great Boldness",
            "Expansion, Promotion",
            "Brilliance Injured",
            "Family",
            "Division, Divergence",
            "Halting, Hardship",
            "Liberation, Solution",
            "Decrease",
            "Increase",
            "Separation",
            "Encountering",
            "Association, Companionship",
            "Growing Upward",
            "Exhaustion",
            "Replenishing, Renewal",
            "Abolishing the Old",
            "Establishing the New",
            "Mobilizing",
            "Immobility",
            "Auspicious Outlook, Infiltration",
            "Marrying",
            "Goal Reached, Ambition Achieved",
            "Travel",
            "Subtle Influence",
            "Overt Influence",
            "Dispersal",
            "Discipline",
            "Staying Focused, Avoid Misrepresentation",
            "Small Surpassing",
            "Completion",
            "Incompletion"
        };

        public const int MaxLines = TrigramFigure.MaxLines * 2;
        public const int MaxValue = 64;

        public HexagramFigure(IEnumerable<Line> bottomUpSequence) : base(bottomUpSequence, MaxLines)
        {
        }

        public int Value
        {
            get
            {
                var upperIndex = new TrigramFigure(Lines.Skip(TrigramFigure.MaxLines).ToArray()).Value;
                var lowerIndex = new TrigramFigure(Lines.Take(TrigramFigure.MaxLines).ToArray()).Value;

                return Lookup[upperIndex, lowerIndex];
            }
        }

        public bool IsReflected
        {
            get
            {
                var lowerSequence = LowerTrigram.Lines.Select(line => line.IsBroken);
                var upperSequence = UpperTrigram.Lines.Select(line => line.IsBroken);

                return lowerSequence.SequenceEqual(upperSequence.Reverse());
            }
        }

        public string Interpretation
        {
            get { return Interpretations[Value - 1]; }
        }

        public TrigramFigure LowerTrigram
        {
            get { return Trigrams.First(); }
        }

        public TrigramFigure UpperTrigram
        {
            get { return Trigrams.Last(); }
        }

        public IEnumerable<TrigramFigure> Trigrams
        {
            get
            {
                return Enumerable
                    .Range(0, MaxLines - 2)
                    .Select(n => new TrigramFigure(Lines.Skip(n).Take(TrigramFigure.MaxLines)));
            }
        }

        public HexagramFigure Reversed()
        {
            return new HexagramFigure(IsReflected ? ToggledLines : Lines.Reverse());
        }

        public static IEnumerable<HexagramFigure> AllFigures
        {
            get { return Enumerable.Range(1, MaxValue).Select(FromValue); }
        }

        public static HexagramFigure FromValue(int value)
        {
            Guard.Against<ArgumentOutOfRangeException>(value < 1 || value > MaxValue, "index");

            var size = Math.Pow(2, TrigramFigure.MaxLines);

            for (var lowerIndex = 0; lowerIndex < size; ++lowerIndex)
                for (var upperIndex = 0; upperIndex < size; ++upperIndex)
                    if (Lookup[upperIndex, lowerIndex] == value)
                        return new HexagramFigure(TrigramFigure.FromValue(lowerIndex).Lines.Concat(TrigramFigure.FromValue(upperIndex).Lines));

            throw new InvalidOperationException();
        }
    }
}